package cn.xdf.docscan

import android.graphics.Bitmap
import android.util.Log
import com.google.mediapipe.framework.Graph
import com.google.mediapipe.framework.Packet
import com.google.mediapipe.framework.PacketCallback
import com.google.mediapipe.framework.PacketGetter
import com.google.mediapipe.framework.ProtoUtil
import java.lang.reflect.Method
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.util.ArrayList

/**
 * 输出处理器
 * 1:1复刻lsa.java、lsb.java、lsc.java的输出处理逻辑
 */
class OutputProcessor {
    
    companion object {
        private const val TAG = "OutputProcessor"
        
        /**
         * 从Packet提取图像
         * 1:1复刻seh.java的逻辑
         */
        private fun extractImageFromPacket(packet: Packet): Bitmap? {
            return try {
                // 1. 获取图像尺寸 - 完全按照seh.java的逻辑
                val width = getImageWidth(packet.nativeHandle)
                val height = getImageHeight(packet.nativeHandle)
                
                // 2. 创建Bitmap - 完全按照seh.java的逻辑
                val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
                
                // 3. 创建ByteBuffer - 完全按照seh.java的逻辑
                val buffer = ByteBuffer.allocateDirect(width * height * 4)
                buffer.order(ByteOrder.nativeOrder())
                
                // 4. 获取图像数据 - 完全按照seh.java的逻辑
                val success = getImageData(packet.nativeHandle, buffer)
                if (!success) {
                    Log.e(TAG, "❌ 获取图像数据失败: ${width}x${height}")
                    return null
                }
                
                // 5. 复制像素数据 - 完全按照seh.java的逻辑
                bitmap.copyPixelsFromBuffer(buffer)
                
                Log.d(TAG, "✅ 成功提取图像: ${width}x${height}")
                bitmap
                
            } catch (e: Exception) {
                Log.e(TAG, "❌ 从Packet提取图像失败", e)
                null
            }
        }
        
        /**
         * 获取protobuf数据
         * 使用成功的方法获取真实的检测数据
         */
        private fun getProtoBytes(packet: Packet): ByteArray {
            return try {
                Log.d(TAG, "🔍 开始获取protobuf数据，packet handle: ${packet.nativeHandle}")
                
                // 直接使用成功的方法：nativeGetProtoBytes
                val protoBytes = getNativeProtoBytes(packet.nativeHandle)
                if (protoBytes.isNotEmpty()) {
                    Log.d(TAG, "✅ 成功获取真实protobuf数据: ${protoBytes.size} bytes")
                    return protoBytes
                }
                
                Log.e(TAG, "❌ 无法获取protobuf数据")
                ByteArray(0)
                
            } catch (e: Exception) {
                Log.e(TAG, "❌ 获取protobuf数据失败", e)
                ByteArray(0)
            }
        }
        
        /**
         * 使用nativeGetProtoBytes方法获取数据
         */
        private fun getNativeProtoBytes(nativeHandle: Long): ByteArray {
            return try {
                val method = PacketGetter::class.java.getDeclaredMethod("nativeGetProtoBytes", Long::class.java)
                method.isAccessible = true
                val result = method.invoke(null, nativeHandle)
                
                if (result is ByteArray) {
                    Log.d(TAG, "✅ nativeGetProtoBytes成功: ${result.size} bytes")
                    return result
                } else {
                    Log.e(TAG, "❌ nativeGetProtoBytes返回类型错误: ${result?.javaClass?.simpleName}")
                    ByteArray(0)
                }
            } catch (e: Exception) {
                Log.e(TAG, "❌ nativeGetProtoBytes调用失败", e)
                ByteArray(0)
            }
        }
        
        /**
         * 尝试获取原始数据
         */
        private fun getRawPacketData(packet: Packet): ByteArray {
            return try {
                // 尝试多种方式获取packet的原始数据
                
                // 方法1: 尝试访问内部字段
                val packetClass = packet.javaClass
                val fields = packetClass.declaredFields
                
                for (field in fields) {
                    field.isAccessible = true
                    val value = field.get(packet)
                    if (value is ByteArray && value.isNotEmpty()) {
                        Log.d(TAG, "找到ByteArray字段: ${field.name}, 大小: ${value.size}")
                        return value
                    }
                }
                
                // 方法2: 尝试使用native方法获取数据
                val nativeData = getNativePacketData(packet)
                if (nativeData.isNotEmpty()) {
                    return nativeData
                }
                
                ByteArray(0)
            } catch (e: Exception) {
                Log.d(TAG, "无法获取原始数据: ${e.message}")
                ByteArray(0)
            }
        }
        
        /**
         * 尝试使用native方法获取数据
         */
        private fun getNativePacketData(packet: Packet): ByteArray {
            return try {
                // 尝试调用packet的native方法
                val packetClass = packet.javaClass
                val methods = packetClass.declaredMethods
                
                for (method in methods) {
                    if (method.name.contains("get") && method.parameterCount == 0) {
                        method.isAccessible = true
                        try {
                            val result = method.invoke(packet)
                            if (result is ByteArray && result.isNotEmpty()) {
                                Log.d(TAG, "找到数据方法: ${method.name}, 大小: ${result.size}")
                                return result
                            }
                        } catch (e: Exception) {
                            // 忽略方法调用失败
                        }
                    }
                }
                
                ByteArray(0)
            } catch (e: Exception) {
                Log.d(TAG, "无法获取native数据: ${e.message}")
                ByteArray(0)
            }
        }
        
        /**
         * 尝试通过ProtoUtil获取数据
         */
        private fun getProtoDataViaProtoUtil(packet: Packet): ByteArray {
            return try {
                // 尝试使用ProtoUtil类
                val protoUtilClass = Class.forName("com.google.mediapipe.framework.ProtoUtil")
                val getProtoMethod = protoUtilClass.getDeclaredMethod("getProto", Packet::class.java)
                getProtoMethod.isAccessible = true
                val result = getProtoMethod.invoke(null, packet)
                if (result is ByteArray) {
                    return result
                }
                ByteArray(0)
            } catch (e: Exception) {
                Log.d(TAG, "无法通过ProtoUtil获取数据: ${e.message}")
                ByteArray(0)
            }
        }
        
        /**
         * 尝试获取SerializedMessage数据
         */
        private fun getSerializedMessageData(packet: Packet): ByteArray {
            return try {
                Log.d(TAG, "🔍 尝试SerializedMessage方法")
                
                // 尝试创建SerializedMessage实例
                val serializedMessageClass = Class.forName("com.google.mediapipe.framework.ProtoUtil\$SerializedMessage")
                val serializedMessage = serializedMessageClass.newInstance()
                
                // 尝试调用nativeGetProto
                val nativeGetProtoMethod = PacketGetter::class.java.getDeclaredMethod(
                    "nativeGetProto",
                    Long::class.java,
                    serializedMessageClass
                )
                nativeGetProtoMethod.isAccessible = true
                nativeGetProtoMethod.invoke(null, packet.nativeHandle, serializedMessage)
                
                // 尝试获取value字段
                val valueField = serializedMessageClass.getDeclaredField("value")
                valueField.isAccessible = true
                val value = valueField.get(serializedMessage)
                if (value is ByteArray) {
                    Log.d(TAG, "✅ SerializedMessage成功获取数据: ${value.size} bytes")
                    return value
                }
                Log.d(TAG, "❌ SerializedMessage返回的不是ByteArray")
                ByteArray(0)
            } catch (e: Exception) {
                Log.d(TAG, "无法获取SerializedMessage数据: ${e.message}")
                ByteArray(0)
            }
        }
        
        /**
         * 尝试其他方式获取数据
         */
        private fun getOtherPacketData(packet: Packet): ByteArray {
            return try {
                Log.d(TAG, "🔍 尝试其他方法获取数据")
                
                // 方法1: 尝试获取packet的所有字段
                val packetClass = packet.javaClass
                Log.d(TAG, "📋 Packet类名: ${packetClass.name}")
                
                val fields = packetClass.declaredFields
                Log.d(TAG, "📋 Packet字段数量: ${fields.size}")
                
                for (field in fields) {
                    field.isAccessible = true
                    val fieldName = field.name
                    val fieldType = field.type.simpleName
                    Log.d(TAG, "📋 字段: $fieldName (类型: $fieldType)")
                    
                    try {
                        val value = field.get(packet)
                        when (value) {
                            is ByteArray -> {
                                Log.d(TAG, "✅ 找到ByteArray字段: $fieldName, 大小: ${value.size}")
                                return value
                            }
                            is Long -> {
                                Log.d(TAG, "📋 Long字段: $fieldName = $value")
                            }
                            is Int -> {
                                Log.d(TAG, "📋 Int字段: $fieldName = $value")
                            }
                            else -> {
                                Log.d(TAG, "📋 其他字段: $fieldName = $value")
                            }
                        }
                    } catch (e: Exception) {
                        Log.d(TAG, "❌ 无法读取字段 $fieldName: ${e.message}")
                    }
                }
                
                // 方法2: 尝试调用packet的所有方法
                val methods = packetClass.declaredMethods
                Log.d(TAG, "📋 Packet方法数量: ${methods.size}")
                
                for (method in methods) {
                    Log.d(TAG, "📋 方法: ${method.name} (参数数量: ${method.parameterCount})")
                    if (method.parameterCount == 0 && method.name.startsWith("get")) {
                        method.isAccessible = true
                        try {
                            val result = method.invoke(packet)
                            Log.d(TAG, "📋 方法 ${method.name} 返回: $result (类型: ${result?.javaClass?.simpleName})")
                            if (result is ByteArray && result.isNotEmpty()) {
                                Log.d(TAG, "✅ 找到数据方法: ${method.name}, 大小: ${result.size}")
                                return result
                            }
                        } catch (e: Exception) {
                            Log.d(TAG, "❌ 方法 ${method.name} 调用失败: ${e.message}")
                        }
                    }
                }
                
                // 方法3: 尝试使用Packet的其他方法
                try {
                    val timestamp = packet.timestamp
                    Log.d(TAG, "📋 Packet时间戳: $timestamp")
                } catch (e: Exception) {
                    Log.d(TAG, "❌ 无法获取时间戳: ${e.message}")
                }
                
                // 方法4: 尝试直接使用native handle获取数据
                val nativeData = getNativePacketDataDirect(packet.nativeHandle)
                if (nativeData.isNotEmpty()) {
                    Log.d(TAG, "✅ 通过native handle获取数据成功: ${nativeData.size} bytes")
                    return nativeData
                }
                
                // 方法5: 尝试使用已知的MediaPipe API
                val mediaPipeData = getMediaPipeData(packet)
                if (mediaPipeData.isNotEmpty()) {
                    Log.d(TAG, "✅ 通过MediaPipe API获取数据成功: ${mediaPipeData.size} bytes")
                    return mediaPipeData
                }
                
                ByteArray(0)
            } catch (e: Exception) {
                Log.d(TAG, "❌ 其他方法获取数据失败: ${e.message}")
                ByteArray(0)
            }
        }
        
        /**
         * 直接使用native handle获取数据
         */
        private fun getNativePacketDataDirect(nativeHandle: Long): ByteArray {
            return try {
                Log.d(TAG, "🔍 尝试直接使用native handle获取数据: $nativeHandle")
                
                // 尝试调用PacketGetter的native方法
                val packetGetterClass = PacketGetter::class.java
                val methods = packetGetterClass.declaredMethods
                
                Log.d(TAG, "📋 PacketGetter方法总数: ${methods.size}")
                
                for (method in methods) {
                    Log.d(TAG, "📋 PacketGetter方法: ${method.name} (参数: ${method.parameterTypes.joinToString()})")
                    
                    // 只尝试安全的protobuf相关方法
                    if (method.name.contains("Proto") && !method.name.contains("Audio")) {
                        method.isAccessible = true
                        try {
                            Log.d(TAG, "🔍 尝试调用方法: ${method.name}")
                            
                            val result = when (method.parameterCount) {
                                1 -> {
                                    if (method.parameterTypes[0] == Long::class.java) {
                                        method.invoke(null, nativeHandle)
                                    } else {
                                        Log.d(TAG, "⚠️ 跳过方法 ${method.name}，参数类型不匹配")
                                        continue
                                    }
                                }
                                2 -> {
                                    // 只尝试已知安全的参数组合
                                    if (method.parameterTypes[0] == Long::class.java) {
                                        when (method.parameterTypes[1]) {
                                            ByteArray::class.java -> {
                                                method.invoke(null, nativeHandle, ByteArray(1024))
                                            }
                                            java.nio.ByteBuffer::class.java -> {
                                                method.invoke(null, nativeHandle, java.nio.ByteBuffer.allocate(1024))
                                            }
                                            else -> {
                                                Log.d(TAG, "⚠️ 跳过方法 ${method.name}，第二个参数类型不支持: ${method.parameterTypes[1]}")
                                                continue
                                            }
                                        }
                                    } else {
                                        Log.d(TAG, "⚠️ 跳过方法 ${method.name}，第一个参数类型不匹配")
                                        continue
                                    }
                                }
                                else -> {
                                    Log.d(TAG, "⚠️ 跳过方法 ${method.name}，参数数量不支持: ${method.parameterCount}")
                                    continue
                                }
                            }
                            
                            Log.d(TAG, "📋 方法 ${method.name} 返回: $result (类型: ${result?.javaClass?.simpleName})")
                            
                            when (result) {
                                is ByteArray -> {
                                    if (result.isNotEmpty()) {
                                        Log.d(TAG, "✅ 方法 ${method.name} 返回ByteArray: ${result.size} bytes")
                                        return result
                                    }
                                }
                                is java.nio.ByteBuffer -> {
                                    if (result.hasRemaining()) {
                                        val bytes = ByteArray(result.remaining())
                                        result.get(bytes)
                                        Log.d(TAG, "✅ 方法 ${method.name} 返回ByteBuffer: ${bytes.size} bytes")
                                        return bytes
                                    }
                                }
                                is Boolean -> {
                                    Log.d(TAG, "📋 方法 ${method.name} 返回Boolean: $result")
                                }
                                is Int -> {
                                    Log.d(TAG, "📋 方法 ${method.name} 返回Int: $result")
                                }
                                else -> {
                                    Log.d(TAG, "📋 方法 ${method.name} 返回其他类型: $result")
                                }
                            }
                        } catch (e: Exception) {
                            Log.d(TAG, "❌ 方法 ${method.name} 调用失败: ${e.message}")
                            // 不抛出异常，继续尝试下一个方法
                        }
                    }
                }
                
                Log.d(TAG, "⚠️ 没有找到合适的protobuf数据获取方法")
                ByteArray(0)
            } catch (e: Exception) {
                Log.d(TAG, "❌ 直接使用native handle获取数据失败: ${e.message}")
                ByteArray(0)
            }
        }
        
        /**
         * 尝试使用已知的MediaPipe API获取数据
         */
        private fun getMediaPipeData(packet: Packet): ByteArray {
            return try {
                Log.d(TAG, "🔍 尝试使用MediaPipe API获取数据")
                
                // 尝试使用Packet的已知方法
                val packetClass = packet.javaClass
                val methods = packetClass.declaredMethods
                
                for (method in methods) {
                    if (method.name == "getProtoBytes" || method.name == "getData" || method.name == "getBytes") {
                        method.isAccessible = true
                        try {
                            val result = method.invoke(packet)
                            if (result is ByteArray && result.isNotEmpty()) {
                                Log.d(TAG, "✅ 找到MediaPipe方法: ${method.name}, 大小: ${result.size}")
                                return result
                            }
                        } catch (e: Exception) {
                            Log.d(TAG, "❌ MediaPipe方法 ${method.name} 调用失败: ${e.message}")
                        }
                    }
                }
                
                // 尝试使用Packet的其他可能方法
                try {
                    // 尝试获取packet的序列化数据
                    val serializedMethod = packetClass.getDeclaredMethod("serialize")
                    serializedMethod.isAccessible = true
                    val serialized = serializedMethod.invoke(packet)
                    if (serialized is ByteArray && serialized.isNotEmpty()) {
                        Log.d(TAG, "✅ 通过serialize方法获取数据: ${serialized.size} bytes")
                        return serialized
                    }
                } catch (e: Exception) {
                    Log.d(TAG, "❌ serialize方法不存在或调用失败: ${e.message}")
                }
                
                ByteArray(0)
            } catch (e: Exception) {
                Log.d(TAG, "❌ MediaPipe API获取数据失败: ${e.message}")
                ByteArray(0)
            }
        }
        
        /**
         * 获取vector packets
         * 1:1复刻lsb.java的逻辑
         */
        private fun getVectorPackets(packet: Packet): ArrayList<Packet> {
            return try {
                val packets = ArrayList<Packet>()
                
                // 使用反射调用nativeGetVectorPackets方法
                val nativeGetVectorPacketsMethod = PacketGetter::class.java.getDeclaredMethod(
                    "nativeGetVectorPackets", 
                    Long::class.java
                )
                nativeGetVectorPacketsMethod.isAccessible = true
                val nativeHandles = nativeGetVectorPacketsMethod.invoke(null, packet.nativeHandle) as LongArray
                
                // 创建Packet对象
                for (handle in nativeHandles) {
                    val newPacket = Packet.create(handle)
                    packets.add(newPacket)
                }
                
                Log.d(TAG, "✅ 成功获取vector packets: ${packets.size}个")
                packets
                
            } catch (e: Exception) {
                Log.e(TAG, "❌ 获取vector packets失败", e)
                ArrayList()
            }
        }
        
        /**
         * 获取图像宽度
         */
        private fun getImageWidth(nativeHandle: Long): Int {
            return try {
                val method = PacketGetter::class.java.getDeclaredMethod("nativeGetImageWidth", Long::class.java)
                method.isAccessible = true
                method.invoke(null, nativeHandle) as Int
            } catch (e: Exception) {
                Log.e(TAG, "❌ 获取图像宽度失败", e)
                0
            }
        }
        
        /**
         * 获取图像高度
         */
        private fun getImageHeight(nativeHandle: Long): Int {
            return try {
                val method = PacketGetter::class.java.getDeclaredMethod("nativeGetImageHeight", Long::class.java)
                method.isAccessible = true
                method.invoke(null, nativeHandle) as Int
            } catch (e: Exception) {
                Log.e(TAG, "❌ 获取图像高度失败", e)
                0
            }
        }
        
        /**
         * 获取图像数据
         */
        private fun getImageData(nativeHandle: Long, buffer: ByteBuffer): Boolean {
            return try {
                val method = PacketGetter::class.java.getDeclaredMethod("nativeGetImageData", Long::class.java, ByteBuffer::class.java)
                method.isAccessible = true
                method.invoke(null, nativeHandle, buffer) as Boolean
            } catch (e: Exception) {
                Log.e(TAG, "❌ 获取图像数据失败", e)
                false
            }
        }
    }
    
    /**
     * 设置输出流回调
     * 完全按照lsm.java的逻辑实现
     */
    fun setupOutputCallbacks(graph: Graph, callback: DocScannerCallback) {
        // 1. 设置output_detections回调 - 完全按照lsa.java的逻辑
        graph.addPacketCallback("output_detections", DetectionCallback(callback))
        
        // 2. 设置output_cropped_frames_rgba回调 - 完全按照lsb.java的逻辑
        graph.addPacketCallback("output_cropped_frames_rgba", CroppedFramesCallback(callback))
        
        // 3. 设置output_original_frame_rgba回调 - 完全按照lsc.java的逻辑
        graph.addPacketCallback("output_original_frame_rgba", OriginalFrameCallback(callback))
        
        Log.d(TAG, "✅ 输出流回调设置完成")
    }
    
    /**
     * 检测结果回调
     * 1:1复刻lsa.java的逻辑
     */
    private class DetectionCallback(private val callback: DocScannerCallback) : PacketCallback {
        override fun process(packet: Packet) {
            try {
                Log.d(TAG, "收到output_detections数据包，时间戳: ${packet.timestamp}")
                
                // 1. 获取protobuf数据 - 完全按照lsa.java的逻辑
                val detectionData = getProtoBytes(packet)
                
                // 3. 发送到回调
                callback.onDetectionResult(detectionData, packet.timestamp)
                
                Log.d(TAG, "✅ 检测结果处理完成，数据大小: ${detectionData.size} bytes")
                
            } catch (e: Exception) {
                Log.e(TAG, "❌ 检测结果处理失败", e)
            }
        }
    }
    
    /**
     * 裁剪帧回调
     * 1:1复刻lsb.java的逻辑
     */
    private class CroppedFramesCallback(private val callback: DocScannerCallback) : PacketCallback {
        override fun process(packet: Packet) {
            try {
                Log.d(TAG, "收到output_cropped_frames_rgba数据包，时间戳: ${packet.timestamp}")
                
                // 1. 获取vector packets - 完全按照lsb.java的逻辑
                val packets = getVectorPackets(packet)
                
                Log.d(TAG, "✅ 成功获取vector packets: ${packets.size}个")
                
                // 2. 转换为Bitmap - 完全按照lsb.java的逻辑
                val bitmaps = ArrayList<Bitmap>()
                for (p in packets) {
                    val bitmap = extractImageFromPacket(p)
                    if (bitmap != null) {
                        bitmaps.add(bitmap)
                    }
                }
                
                // 3. 发送到回调
                callback.onCroppedFramesResult(bitmaps, packet.timestamp)
                
                Log.d(TAG, "✅ 裁剪帧处理完成，图像数量: ${bitmaps.size}")
                
            } catch (e: Exception) {
                Log.e(TAG, "❌ 裁剪帧处理失败", e)
            }
        }
    }
    
    /**
     * 原始帧回调
     * 1:1复刻lsc.java的逻辑
     */
    private class OriginalFrameCallback(private val callback: DocScannerCallback) : PacketCallback {
        override fun process(packet: Packet) {
            try {
                Log.d(TAG, "收到output_original_frame_rgba数据包，时间戳: ${packet.timestamp}")
                
                // 1. 转换为Bitmap - 完全按照lsc.java的逻辑
                val bitmap = extractImageFromPacket(packet)
                
                // 2. 发送到回调
                if (bitmap != null) {
                    callback.onOriginalFrameResult(bitmap, packet.timestamp)
                    Log.d(TAG, "✅ 原始帧处理完成，图像尺寸: ${bitmap.width}x${bitmap.height}")
                } else {
                    Log.w(TAG, "⚠️ 原始帧转换为Bitmap失败")
                }
                
            } catch (e: Exception) {
                Log.e(TAG, "❌ 原始帧处理失败", e)
            }
        }
    }
    

    
    /**
     * DocScanner回调接口
     */
    interface DocScannerCallback {
        fun onDetectionResult(detectionData: ByteArray, timestamp: Long)
        fun onCroppedFramesResult(bitmaps: List<Bitmap>, timestamp: Long)
        fun onOriginalFrameResult(bitmap: Bitmap, timestamp: Long)
    }
} 